package com.carrot.gateway.app;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.carrot.auth.constants.JwtConstants;
import com.carrot.common.core.domain.R;
import com.carrot.common.enums.ErrorCodeEnum;
import com.carrot.gateway.constant.RedisConstants;
import com.carrot.gateway.entity.ClientCertificate;
import com.carrot.gateway.entity.dto.LoginDto;
import com.carrot.gateway.entity.dto.TokenDto;
import com.carrot.gateway.entity.vo.TokenVo;
import com.carrot.gateway.entity.vo.UserVo;
import com.carrot.gateway.property.SecurityOAuth2Properties;
import com.carrot.gateway.uaa.IUaaRequestService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.concurrent.TimeUnit;

/**
 * 鉴权服务类
 */

@Service
@AllArgsConstructor
@Slf4j
public class AuthAppServiceImpl implements IAuthAppService {

    private final RedisTemplate<String, Object> redisTemplate;

    private final IUaaRequestService iUaaRequestService;
    private final SecurityOAuth2Properties securityOAuth2Properties;

    @Override
    public R getToken(String code, String redirectUri, String appName) {

        //获取token
        R<TokenVo> resultWrapper = iUaaRequestService.getTokenByCode(code, redirectUri, appName);
        if(resultWrapper.getCode() == ErrorCodeEnum.CODE_ERROR.getCode()){
            return resultWrapper;
        }
        TokenVo tokenVo = resultWrapper.getData();

        //获取用户
        R<UserVo> userResult = iUaaRequestService.getUser(tokenVo.getAccessToken());
        if(userResult.getCode() == ErrorCodeEnum.CODE_ERROR.getCode()){
           return userResult;
        }
        UserVo userVo = userResult.getData();

        //缓存token和用户 TODO
        cacheTokenAndUser(tokenVo,userVo);

        return R.ok(tokenVo);
    }

    @Override
    public R login(LoginDto loginDto) {
        //获取客户端凭证
        ClientCertificate clientCertificate = ClientCertificate.build(loginDto.getAppName(), securityOAuth2Properties);
        //调用UAA认证接口
        return iUaaRequestService.getTokenByPassword(loginDto,clientCertificate);
    }

    @Override
    public R getSmsCaptcha(String phone,String appName) {
        //获取客户端凭证
        ClientCertificate clientCertificate = ClientCertificate.build(appName, securityOAuth2Properties);
        return iUaaRequestService.getSmsCaptcha(phone,clientCertificate);
    }

    @Override
    public R getTokenByRefreshToken(String refreshToken, String appName,String clientIp) {
        //获取客户端凭证
        ClientCertificate clientCertificate = ClientCertificate.build(appName, securityOAuth2Properties);
        //调用UAA认证接口
        return iUaaRequestService.getTokenByRefreshToken(refreshToken,clientCertificate,clientIp);
    }

    @Override
    public R outLogin(ServerHttpRequest request, TokenDto token) {
        //获取客户端凭证
        ClientCertificate clientCertificate = ClientCertificate.build(token.getAppName(), securityOAuth2Properties);
        //获取token
        String revocationToken = token.getRefreshToken();
        if(StringUtils.isEmpty(revocationToken)){
            String accessToken =request.getHeaders().getFirst(JwtConstants.TOKEN_HEADER);
            revocationToken= StrUtil
                    .emptyToDefault(accessToken,"")
                    .replace(JwtConstants.TOKEN_HEAD, "");
        }
        //调用UAA服务接口
        return iUaaRequestService.revocationToken(revocationToken,clientCertificate);
    }

    public void cacheTokenAndUser(TokenVo tokenVO, UserVo userVO){
         //访问令牌key
         String accessTokenKey = RedisConstants.AUTHORIZATION_ACCESS_TOKEN_PREFIX_KEY+tokenVO.getAccessToken();
         String userAccessTokenKey = RedisConstants.AUTHORIZATION_USER_ACCESS_TOKEN_PREFIX_KEY+userVO.getUid();
         //访问令牌过期时间
         long now = Instant.now().getEpochSecond();;
         long exp = Long.parseLong(userVO.getExp())-now;

         //缓存token和用户信息
         redisTemplate.opsForValue().set(accessTokenKey,JSONUtil.toJsonStr(userVO),exp, TimeUnit.SECONDS);
         redisTemplate.opsForValue().set(userAccessTokenKey,tokenVO.getAccessToken(),exp,TimeUnit.SECONDS);
    }



}
